package com.zhz.common.feign;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.cloud.netflix.ribbon.RibbonApplicationContextInitializer;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.lang.NonNull;

import java.util.*;

/**
 * FeignClientInitializer
 * <p>
 * Ribbon 默认是采用懒加载, 即第一次访问时才会去创建 LoadBalanceClient, 导致第一次请求时可能会造成超时.
 * 这里主动扫描所有依赖的服务并提前加载
 *
 * @author zhouhengzhe
 */
public class FeignClientInitializer extends RibbonApplicationContextInitializer implements ApplicationContextAware {

    private ApplicationContext applicationContext;
    private final List<String> clientNames;


    public FeignClientInitializer(SpringClientFactory springClientFactory) {
        this(springClientFactory, new ArrayList<>());
    }


    private FeignClientInitializer(SpringClientFactory springClientFactory, List<String> clientNames) {
        super(springClientFactory, clientNames);
        this.clientNames = clientNames;
    }


    @Override
    protected void initialize() {
        Map<String, Object> feignClients = this.applicationContext.getBeansWithAnnotation(FeignClient.class);
        if (CollUtil.isEmpty(feignClients)) {
            return;
        }

        Set<String> serviceNames = new HashSet<>();
        for (String beanName : feignClients.keySet()) {
            FeignClient feignClient = this.applicationContext.findAnnotationOnBean(beanName, FeignClient.class);
            Objects.requireNonNull(feignClient);
            String serviceName = StrUtil.blankToDefault(feignClient.value(), feignClient.name());
            serviceNames.add(serviceName);
        }

        if (CollUtil.isNotEmpty(serviceNames)) {
            this.clientNames.addAll(serviceNames);
        }

        super.initialize();
    }


    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }


}
